package kp.rpc.serializer;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import kp.rpc.model.RpcRequest;
import kp.rpc.model.RpcResponse;

import java.io.IOException;

/**
 * @author tzf
 * {@code @description:} json序列化器
 */

public class JsonSerializer implements Serializer {
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    /**
     * 序列化
     *
     * @param object 对象
     * @return 序列化后的字节数组
     * @throws IOException 序列化异常
     */
    @Override
    public <T> byte[] serialize(T object) throws IOException {
        //写成字节数组返回
        return OBJECT_MAPPER.writeValueAsBytes(object);
    }

    /**
     * 反序列化
     *
     * @param bytes 字节数组
     * @param type  类型
     * @return 反序列化后的对象
     * @throws IOException 反序列化异常
     */
    @Override
    public <T> T deserialize(byte[] bytes, Class<T> type) throws IOException {
        T t = OBJECT_MAPPER.readValue(bytes, type);
        //对序列化后的值做判断
        if (t instanceof RpcRequest) {
            return handlerRequest((RpcRequest) t, type);
        }
        if (t instanceof RpcResponse) {
            return handlerResponse((RpcResponse) t, type);
        }
        return t;
    }

    private <T> T handlerResponse(RpcResponse rpcResponse, Class<T> type) throws IOException {
        // 处理响应数据
        byte[] dataBytes = OBJECT_MAPPER.writeValueAsBytes(rpcResponse.getData());
        rpcResponse.setData(OBJECT_MAPPER.readValue(dataBytes, rpcResponse.getDataType()));
        return type.cast(rpcResponse);
    }

    private <T> T handlerRequest(RpcRequest rpcRequest, Class<T> type) throws IOException {
        Class<?>[] parameterTypes = rpcRequest.getParameterTypes();
        Object[] args = rpcRequest.getArgs();
        for (int i = 0; i < parameterTypes.length; i++) {
            Class<?> parameterType = parameterTypes[i];
            Object arg = args[i];
            // 如果类型不同，则重新处理一下类型 long->string
            if (!parameterType.isAssignableFrom(arg.getClass())) {
                args[i] = OBJECT_MAPPER.convertValue(arg, parameterType);
            }
        }
        return type.cast(rpcRequest);
    }
}
